package com.better.common.mongo.repository;

import com.mongodb.BasicDBList;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;

import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Pattern;

import org.bson.BSON;
import org.springframework.data.domain.Example;
import org.springframework.data.geo.Circle;
import org.springframework.data.geo.Point;
import org.springframework.data.geo.Shape;
import org.springframework.data.mongodb.InvalidMongoDbApiUsageException;
import org.springframework.data.mongodb.core.geo.GeoJson;
import org.springframework.data.mongodb.core.geo.Sphere;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.GeoCommand;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.Map.Entry;

/**
 * 解决用标准查询无法获取查询额KEY，导致无法正常分页（嵌套查询）
 * Created by Administrator on 2018/1/19.
 */
public class NestCriteria extends org.springframework.data.mongodb.core.query.Criteria {

    private static ConcurrentMap<String, String> concurrentMapWordCounts = new ConcurrentHashMap<>();

    public Map<String, String> getkey() {
        return concurrentMapWordCounts;
    }

    public NestCriteria() {
        super();
    }

    public NestCriteria(String key) {
        super(key);
    }

    protected NestCriteria(List<Criteria> criteriaChain, String key) {
        super(criteriaChain, key);
    }

    public static Criteria where(String key) {
        concurrentMapWordCounts.put(key, key);
        return new Criteria(key);
    }

    public static Criteria byExample(Object example) {
        return byExample(Example.of(example));
    }

    public static Criteria byExample(Example<?> example) {
        return (new Criteria()).alike(example);
    }

    public Criteria and(String key) {
        concurrentMapWordCounts.put(key, key);
        return super.and(key);
    }

    public Criteria is(Object o) {
        return super.is(o);
    }

    public Criteria ne(Object o) {
        super.ne(o);
        return null;
    }

    public Criteria lt(Object o) {
        return super.lt(o);
    }

    public Criteria lte(Object o) {
        return super.lte(o);
    }

    public Criteria gt(Object o) {
        return super.gt(o);
    }

    public Criteria gte(Object o) {
        return super.gte(o);
    }

    public Criteria in(Object... o) {
       return super.in(o);
    }

    public Criteria in(Collection<?> c) {
        return super.in(c);
    }

    public Criteria nin(Object... o) {
        return this.nin((Collection) Arrays.asList(o));
    }

    public Criteria nin(Collection<?> o) {
        return super.nin(o);
    }

    public Criteria mod(Number value, Number remainder) {
        return super.mod(value,remainder);
    }

    public Criteria all(Object... o) {
        return this.all((Collection) Arrays.asList(o));
    }

    public Criteria all(Collection<?> o) {
        return super.all(o);
    }

    public Criteria size(int s) {
        return super.size(s);
    }

    public Criteria exists(boolean b) {
        return  super.exists(b);
    }

    public Criteria type(int t) {
        return super.type(t);
    }

    public Criteria not() {
        return  super.not();
    }


    public Criteria regex(String re) {
        return this.regex(re, (String) null);
    }

    public Criteria regex(String re, String options) {
        return this.regex(this.toPattern(re, options));
    }

    public Criteria regex(Pattern pattern) {
        Criteria criteria = super.regex(pattern);
        return criteria;
    }

    private Pattern toPattern(String regex, String options) {
        Assert.notNull(regex, "Regex string must not be null!");
        return Pattern.compile(regex, options == null ? 0 : BSON.regexFlags(options));
    }

    public Criteria withinSphere(Circle circle) {
        return super.withinSphere(circle);
    }

    public Criteria within(Shape shape) {
        return super.within(shape);
    }

    public Criteria near(Point point) {
        return super.near(point);
    }

    public Criteria nearSphere(Point point) {
        return super.nearSphere(point);
    }

    public Criteria intersects(GeoJson geoJson) {
        return super.intersects(geoJson);
    }

    public Criteria maxDistance(double maxDistance) {
       return super.maxDistance(maxDistance);
    }

    public Criteria minDistance(double minDistance) {
      return super.minDistance(minDistance);
    }

    public Criteria elemMatch(NestCriteria c) {
      return super.elemMatch(c);
    }

    public Criteria alike(Example<?> sample) {
       return super.alike(sample);
    }

    public Criteria orOperator(Criteria... criteria) {
      return super.orOperator(criteria);
    }

    public Criteria norOperator(Criteria... criteria) {
      return super.norOperator(criteria);
    }

    public Criteria andOperator(Criteria... criteria) {
       return super.andOperator(criteria);
    }


    public String getKey() {
        return super.getKey();
    }

    public DBObject getCriteriaObject() {
       return super.getCriteriaObject();
    }

    protected DBObject getSingleCriteriaObject() {
        return super.getSingleCriteriaObject();
    }


    public boolean equals(Object obj) {
       return super.equals(obj);
    }


    private boolean isEqual(Object left, Object right) {
        return left == null ? right == null : (left instanceof Pattern ? (right instanceof Pattern ? ((Pattern) left).pattern().equals(((Pattern) right).pattern()) : false) : ObjectUtils.nullSafeEquals(left, right));
    }

    public int hashCode() {
      return super.hashCode();
    }
}
